package com.stu.stusystem.service;

import com.stu.stusystem.common.ApiException;
import com.stu.stusystem.mapper.UserLogMapper;
import com.stu.stusystem.mapper.system.DocumentMapper;
import com.stu.stusystem.mapper.system.StuMapper;
import com.stu.stusystem.model.UserLog;
import com.stu.stusystem.model.em.Jurisdiction;
import com.stu.stusystem.model.system.Document;
import com.stu.stusystem.model.system.StuUser;
import com.stu.stusystem.service.dto.RegisterDTO;
import com.stu.stusystem.service.dto.StuUserDTO;
import com.stu.stusystem.service.vo.LoginVO;
import com.stu.stusystem.util.CopyBeanUtil;
import com.stu.stusystem.util.IPUtil;
import com.stu.stusystem.util.UUIDUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.crypto.hash.Sha1Hash;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import tk.mybatis.mapper.entity.Example;
import tk.mybatis.mapper.weekend.WeekendSqls;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.util.Date;
import java.util.List;

/**
 * @author cxt
 * @date 2020/9/14
 */
@Slf4j
@Service
public class LoginService {

    private UserLogMapper userLogMapper;

    private StuMapper stuMapper;

    private DocumentMapper documentMapper;

    /**
     * 登录验证
     */
    public LoginVO verification(StuUserDTO stu, HttpServletRequest request) {
        String password = new Sha1Hash(stu.getPassword(), stu.getAccount(), 5).toBase64();
        UsernamePasswordToken token = new UsernamePasswordToken(stu.getAccount(), password, stu.getVerification());
        Subject currentUser = SecurityUtils.getSubject();
        try {
            currentUser.login(token);
            userLogMapper.insert(new UserLog(UUIDUtil.generate(), stu.getAccount(), IPUtil.getIpAddr(request), new Date(), "login"));
            log.info("《账号：" + stu.getAccount() + "》登录成功");
        } catch (UnknownAccountException | IncorrectCredentialsException uae) {
            log.debug("登录失败：" + uae);
            throw new ApiException(ApiException.COUNT_AND_PASSWORD_ERROR);
        } catch (LockedAccountException lae) {
            log.info("LockedAccountException");
            throw new ApiException(ApiException.COUNT_EXCEPTION);
        } catch (ExcessiveAttemptsException eae) {
            log.info("ExcessiveAttemptsException");
            throw new ApiException(ApiException.ERROR_MANY_TIMES);
        } catch (AuthenticationException ae) {
            log.info("AuthenticationException");
        }
        String authorization = (String) currentUser.getSession().getId();
        StuUser user = (StuUser) SecurityUtils.getSubject().getPrincipal();
        // 查询用户头像
        Document document = this.documentMapper.selectByPrimaryKey(user.getHeadImg());
        String headImg = "/static/img/head.gif";
        if (document != null) {
            headImg = document.getFilePath();
        }
        return new LoginVO(user.getId(), user.getAccount(), user.getName(), user.getClassId(), user.getIdCard(), user.getPhone(), user.getHeadImg(), headImg, authorization);
    }

    /**
     * 验证码验证
     */
    public void verification(String newCode, HttpServletRequest request) {
        if (newCode.isEmpty()) {
            throw new ApiException("验证码不能为空");
        }
        HttpSession session = request.getSession();
        String code = (String) session.getAttribute("RANDOMVALIDATECODEKEY");
        if (code == null) {
            throw new ApiException("获取验证码失败,请刷新页面");
        }
        String c = code.toLowerCase();
        String v = newCode.toLowerCase();
        if (!v.equals(c)) {
            throw new ApiException("验证码错误");
        }
    }

    /**
     * 注册账号
     */
    public void register(RegisterDTO registerDTO) {
        List<StuUser> stuUsers = stuMapper.selectByExample(new Example.Builder(StuUser.class).where(WeekendSqls.<StuUser>custom().andEqualTo(StuUser::getAccount, registerDTO.getAccount())).build());
        if (stuUsers.isEmpty()) {
            if (registerDTO.getPassword() == null){
                registerDTO.setPassword("1");
            }
            String password = new Sha1Hash(registerDTO.getPassword(), registerDTO.getAccount(), 5).toBase64();
            registerDTO.setPassword(password);
            StuUser stuUser = CopyBeanUtil.copyBean(registerDTO, StuUser.class);
            StuUser user = (StuUser) SecurityUtils.getSubject().getPrincipal();
            if (user != null) {
                stuUser.setCreateBy(user.getName());
            } else {
                stuUser.setCreateBy(registerDTO.getName());
            }
            stuUser.setId(UUIDUtil.generate());
            stuUser.setJurisdiction(Jurisdiction.STUDENT);
            stuUser.setCreateTime(new Date());
            int insert = stuMapper.insert(stuUser);
            if (insert != 1) {
                throw new ApiException(ApiException.SAVE_FAIL);
            }
        } else {
            throw new ApiException("注册账号已存在");
        }
    }

    /**
     * 更新账号密码
     */
    public String updateUserPwd(String id, String oldPwd, String newPwd) {
        StuUser stuUser = this.stuMapper.selectByPrimaryKey(id);
        if (stuUser == null) {
            throw new ApiException(ApiException.CAN_NOT_FIND);
        }
        String olderPwd = new Sha1Hash(oldPwd, stuUser.getAccount(), 5).toBase64();
        if (!stuUser.getPassword().equals(olderPwd)) {
            throw new ApiException(ApiException.PASSWORD_ERROR);
        }
        String s = new Sha1Hash(newPwd, stuUser.getAccount(), 5).toBase64();
        stuUser.setPassword(s);
        StuUser user = (StuUser) SecurityUtils.getSubject().getPrincipal();
        stuUser.setUpdateBy(user.getName());
        stuUser.setUpdateTime(new Date());
        int i = this.stuMapper.updateByExampleSelective(stuUser, new Example.Builder(StuUser.class)
                .where(WeekendSqls.<StuUser>custom().andEqualTo(StuUser::getId, id)).build());
        if (i != 1) {
            throw new ApiException(ApiException.UPDATE_FAIL);
        }
        return stuUser.getAccount();
    }

    /**
     * 登出
     */
    public void logout(HttpServletRequest request) {
        Subject currentUser = SecurityUtils.getSubject();
        StuUser principal = (StuUser) currentUser.getPrincipal();
        userLogMapper.insert(new UserLog(UUIDUtil.generate(), principal.getAccount(), IPUtil.getIpAddr(request), new Date(), "logout"));
        currentUser.logout();
        log.info("《账号：{}》退出系统成功", principal.getAccount());
    }

    @Autowired
    public void setUserLogMapper(UserLogMapper userLogMapper) {
        this.userLogMapper = userLogMapper;
    }

    @Autowired
    public void setStuMapper(StuMapper stuMapper) {
        this.stuMapper = stuMapper;
    }

    @Autowired
    public void setDocumentMapper(DocumentMapper documentMapper) {
        this.documentMapper = documentMapper;
    }
}
